/*
 * @brief Multicore blinky example (Master or slave
 *
 * @note
 * Copyright(C) NXP Semiconductors, 2014
 * All rights reserved.
 *
 * @par
 * Software that is described herein is for illustrative purposes only
 * which provides customers with programming information regarding the
 * LPC products.  This software is supplied "AS IS" without any warranties of
 * any kind, and NXP Semiconductors and its licensor disclaim any and
 * all warranties, express or implied, including all implied warranties of
 * merchantability, fitness for a particular purpose and non-infringement of
 * intellectual property rights.  NXP Semiconductors assumes no responsibility
 * or liability for the use of the software, conveys no license or rights under any
 * patent, copyright, mask work right, or any other intellectual property rights in
 * or to any products. NXP Semiconductors reserves the right to make changes
 * in the software without notification. NXP Semiconductors also makes no
 * representation or warranty that such application will be suitable for the
 * specified use without further testing or modification.
 *
 * @par
 * Permission to use, copy, modify, and distribute this software and its
 * documentation is hereby granted, under NXP Semiconductors' and its
 * licensor's relevant copyrights in the software, without fee, provided that it
 * is used in conjunction with NXP Semiconductors microcontrollers.  This
 * copyright, permission, and disclaimer notice must appear in all copies of
 * this code.
 */

#if 0
#include "board.h"

/** @defgroup PERIPH_M0SLAVE_5410X Multicore blinky example (M0 as slave)
 * @ingroup EXAMPLES_CORE_5410X
 * @include "multicore\m0slave_blinky\readme.txt"
 */

/**
 * @}
 */

/*****************************************************************************
 * Private types/enumerations/variables
 ****************************************************************************/

static MBOX_IDX_T myCoreBox, otherCoreBox;

/*****************************************************************************
 * Public types/enumerations/variables
 ****************************************************************************/

/* Made global to better debug the LED states */
uint32_t sharedLEDStates;

/* Clock rate on the CLKIN pin */
const uint32_t ExtClockIn = 12000000;

extern uint32_t __Vectors;

/*****************************************************************************
 * Private functions
 ****************************************************************************/

/* Hardware mutex take function */
static void mutexTake(void)
{
	/* Wait forever until we can get the mutex */
	while (Chip_MBOX_GetMutex(LPC_MBOX) == 0) {}
}

/* Hardware mutex put function */
static void mutexGive(void)
{
	Chip_MBOX_SetMutex(LPC_MBOX);
}

/* Toggle the LED bit for a core */
static void ledToggleBit(int bitLoc)
{
	sharedLEDStates = sharedLEDStates ^ (1 << bitLoc);
}

/*****************************************************************************
 * Public functions
 ****************************************************************************/

/**
 * @brief	Handle interrupt from mailbox
 * @return	Nothing
 */
void MAILBOX_IRQHandler(void)
{
	/* Slave core uses passed mailbox value as address to shared LED state values */
	uint32_t *psharedLEDStates = (uint32_t *) Chip_MBOX_GetValue(LPC_MBOX, myCoreBox);

	/* Toggle LED bit state for this core usign mutex */
	mutexTake();
	sharedLEDStates = *psharedLEDStates;
	ledToggleBit(1);
	*psharedLEDStates = sharedLEDStates;
	mutexGive();

	/* Clear this MCU's mailbox */
	Chip_MBOX_ClearValueBits(LPC_MBOX, myCoreBox, 0xFFFFFFFF);

	/* Signal master code about the change */
	Chip_MBOX_SetValue(LPC_MBOX, otherCoreBox, 1);
}

/**
 * @brief	main routine for blinky example
 * @return	Function should not exit.
 */
int main(void)
{
	SystemCoreClockUpdate();

	/* Get the mailbox identifiers to the core this code is running and the
	   other core */
	myCoreBox = MAILBOX_CM0PLUS;
	otherCoreBox = MAILBOX_CM4;

	/* M4 core initializes the mailbox */
	/* ROM will setup VTOR to point to the M0 vector table in FLASH
	   prior to booting the M0 image. */

	/* Enable mailbox interrupt */
	NVIC_EnableIRQ(MAILBOX_IRQn);

	while (1) {
		/* Put chip to sleep via WFI instruction */
		__WFI();
	}

	return 0;
}
#endif



#include "app_type.h"
#include "app_cfg.h"
#include "vsfsm_cfg.h"
#include "tool/buffer/buffer.h"
#include "framework/vsfsm/vsfsm.h"
#include "framework/vsftimer/vsftimer.h"
#include "board.h"
#include "chip.h"

const uint32_t ExtClockIn = 0;
static uint32_t system_tick = 0;

static UART_HANDLE_T hUART;
static uint32_t drv_mem[64];

static void  Board_UART_Done(UART_HANDLE_T hUART, UART_EVENT_T ev, void *arg)
{
	if (ev == UART_RX_DONE) {
		*(int *) ROM_UART_HANDLE_TOUDATA(hUART) = 1;
	}
}
void Board_UARTPutSTR(char *str)
{
	ROM_UART_Send(hUART, str, strlen(str));
	ROM_UART_WaitTx(hUART);
}
void print_tick()
{
	uint8_t back[2] = {0x8, 0x0};

	uint8_t digit, i;
	uint32_t tick = system_tick;
	Board_UARTPutSTR("Cur Tick is:         ms");
	Board_UARTPutSTR(back);

	for( i = 0; i < 8; i++)
	{
		digit = tick % 10;
		tick = tick / 10;
		Board_UARTPutSTR(back);
		Board_UARTPutSTR(back);
		switch (digit)
		{
		case 1:
			Board_UARTPutSTR("1");
			break;
		case 2:
			Board_UARTPutSTR("2");
			break;
		case 3:
			Board_UARTPutSTR("3");
			break;
		case 4:
			Board_UARTPutSTR("4");
			break;
		case 5:
			Board_UARTPutSTR("5");
			break;
		case 6:
			Board_UARTPutSTR("6");
			break;
		case 7:
			Board_UARTPutSTR("7");
			break;
		case 8:
			Board_UARTPutSTR("8");
			break;
		case 9:
			Board_UARTPutSTR("9");
			break;
		case 0:
			Board_UARTPutSTR("0");
			break;
		}
		if (tick == 0)
			break;
	}
	Board_UARTPutSTR("\r\n");
}

static void board_uart_init()
{
	UART_CFG_T cfg;
	UART_BAUD_T baud;
	static int cval;

	STATIC const PINMUX_GRP_T pinmuxing[] = {
		/* UART0 */
		{0, 0,  (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN)},	/* UART0 RX */
		{0, 1,  (IOCON_FUNC1 | IOCON_MODE_INACT | IOCON_DIGITAL_EN)},	/* UART0 TX */
	};

	Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_INPUTMUX);
	Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_IOCON);
	Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_USART0);
	Chip_Clock_EnablePeriphClock(SYSCON_CLOCK_FRG);

	Chip_IOCON_SetPinMuxing(LPC_IOCON, pinmuxing, sizeof(pinmuxing) / sizeof(PINMUX_GRP_T));

	hUART = ROM_UART_Init(drv_mem, (uint32_t) LPC_USART0, &cval);

	baud.clk = Chip_Clock_GetAsyncSyscon_ClockRate();	/* Clock frequency */
	baud.baud = 115200;	/* Required baud rate */
	baud.ovr = 0;	/* Set the oversampling to the recommended rate */
	baud.mul = baud.div = 0;
	if (ROM_UART_CalBaud(&baud) != LPC_OK)
	{
		/* Unable to calculate the baud rate parameters */
		hUART = NULL;
		return;
	}
	Chip_SYSCON_SetUSARTFRGCtrl(baud.mul, 0xFF);
	/* Configure the UART */
	cfg.cfg = UART_CFG_8BIT;
	cfg.div = baud.div;	/* Use the calculated div value */
	cfg.ovr = baud.ovr;	/* Use oversampling rate from baud */
	cfg.res = UART_BIT_DLY(115200);

	/* Configure the UART */
	ROM_UART_Configure(hUART, &cfg);
	ROM_UART_RegisterCB(hUART, UART_CB_DONE, Board_UART_Done);
}


#if 0
void UTICK_IRQHandler(void)
{
	Chip_UTICK_ClearInterrupt(LPC_UTICK);
	system_tick++;
	vsftimer_callback_int();
}
static void board_utick_init(void)
{
	Chip_SYSCON_PowerUp(SYSCON_PDRUNCFG_PD_WDT_OSC);
	Chip_UTICK_Init(LPC_UTICK);
	Chip_UTICK_ClearInterrupt(LPC_UTICK);
	Chip_UTICK_SetDelayMs(LPC_UTICK, 1, true);
	Chip_SYSCON_EnableWakeup(SYSCON_STARTER_UTICK);
	NVIC_EnableIRQ(UTICK_IRQn);
}
#endif


uint32_t get_system_tick(void)
{
	return system_tick;
}
void wfi_handle(void)
{
	__WFI();
}
void timer0_set_interval(uint32_t ms)
{
	uint32_t temp = LPC_TIMER0->MR[1] / (Chip_Clock_GetAsyncSyscon_ClockRate() / 1000);
	if (ms > temp)
	{
		Chip_TIMER_Disable(LPC_TIMER0);
		Chip_TIMER_SetMatch(LPC_TIMER0, 1, ((Chip_Clock_GetAsyncSyscon_ClockRate() / 1000) * ms));
		Chip_TIMER_Enable(LPC_TIMER0);
	}
}

void CT32B0_IRQHandler(void)
{
	if (Chip_TIMER_MatchPending(LPC_TIMER0, 1))
	{
		Chip_TIMER_ClearMatch(LPC_TIMER0, 1);
		system_tick += LPC_TIMER0->MR[1] / (Chip_Clock_GetAsyncSyscon_ClockRate() / 1000);
		Chip_TIMER_SetMatch(LPC_TIMER0, 1, (Chip_Clock_GetAsyncSyscon_ClockRate() / 1000));
		vsftimer_callback_int();
	}
}



#define EVENT_1_USER_LOCAL_SCANF		(VSFSM_EVT_USER_LOCAL + 1)
static struct vsfsm_state_t *
event_1_handler(struct vsfsm_t *sm, vsfsm_evt_t evt);
struct vsfsm_t event_1_sm =
{
	{event_1_handler},
};
static struct vsftimer_timer_t event_1_timer =
{
	5000,
	&event_1_sm,
	EVENT_1_USER_LOCAL_SCANF,
};

struct vsfsm_state_t *
event_1_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
	switch (evt)
	{
	case VSFSM_EVT_INIT:
		vsftimer_register(&event_1_timer);
		break;
	case EVENT_1_USER_LOCAL_SCANF:
		Board_UARTPutSTR("event 1\r\n");
		print_tick();
		break;
	default:
		break;
	}

	return NULL;
}


#define EVENT_2_USER_LOCAL_SCANF		(VSFSM_EVT_USER_LOCAL + 1)
static struct vsfsm_state_t *
event_2_handler(struct vsfsm_t *sm, vsfsm_evt_t evt);
struct vsfsm_t event_2_sm =
{
	{event_2_handler},
};
static struct vsftimer_timer_t event_2_timer =
{
	3000,
	&event_2_sm,
	EVENT_2_USER_LOCAL_SCANF,
};

struct vsfsm_state_t *
event_2_handler(struct vsfsm_t *sm, vsfsm_evt_t evt)
{
	switch (evt)
	{
	case VSFSM_EVT_INIT:
		vsftimer_register(&event_2_timer);
		break;
	case EVENT_2_USER_LOCAL_SCANF:
		Board_UARTPutSTR("event 2\r\n");
		print_tick();
		break;
	default:
		break;
	}

	return NULL;
}



int main(void)
{
	Chip_TIMER_Init(LPC_TIMER0);
	Chip_TIMER_PrescaleSet(LPC_TIMER0, 1);
	Chip_TIMER_Reset(LPC_TIMER0);
	Chip_TIMER_MatchEnableInt(LPC_TIMER0, 1);
	Chip_TIMER_SetMatch(LPC_TIMER0, 1, Chip_Clock_GetAsyncSyscon_ClockRate() / 1000);
	Chip_TIMER_ResetOnMatchEnable(LPC_TIMER0, 1);
	NVIC_ClearPendingIRQ(CT32B0_IRQn);
	NVIC_EnableIRQ(CT32B0_IRQn);
	Chip_TIMER_Enable(LPC_TIMER0);

	vsftimer_init();
	vsftimer_wfi_init(timer0_set_interval, wfi_handle);


	vsfsm_init(&event_1_sm);
	vsfsm_init(&event_2_sm);

	while (1)
	{
		vsfsm_poll();

		vsf_enter_critical();
		if (!vsfsm_get_event_pending())
		{
			vsftimer_wfi();
		}
		else
		{
			vsf_leave_critical();
		}
	}

	return 0;
}

